import * as mqtt from 'mqtt/dist/mqtt';
import { App } from 'vue';
import { mqttKey } from './injectionSymbols';

export interface MQTTClient {
  publicTo(
    topic: string,
    message: string | Buffer,
    opts: mqtt.IClientPublishOptions,
    callback?: mqtt.PacketCallback | undefined
  ): void;
  reconnect(options?: mqtt.IClientOptions | undefined): void;
  on(type: string, callback: Function): void;
  off(type: string): void;
  subscribe(
    topic: string | string[],
    opts: mqtt.IClientSubscribeOptions,
    callback?: mqtt.ClientSubscribeCallback | undefined
  ): void;
  unsubscribe(
    topic: string | string[],
    opts?: Object | undefined,
    callback?: mqtt.PacketCallback | undefined
  ): void;
  destroy(): void;
  install(app: App): void;
}

export function createMQTT(brokerUrl: any, options: mqtt.IClientOptions | undefined): MQTTClient {
  let client: mqtt.MqttClient | null = null;
  const events: { [key: string]: Function } = {};

  // mqtt链接
  try {
    destroy();
    client = mqtt.connect(brokerUrl, options);
  } catch (error) {
    console.log('mqtt connect error', error);
  }

  client?.on('connect', () => {
    console.log(new Date().toLocaleTimeString(),'Connection succeeded!');
  });

  client?.on('error', (error) => {
    console.log(new Date().toLocaleTimeString(),'Connection failed', error);
  });

  client?.on('message', (topic, message) => {
    emit(topic, message);
  });

  client?.on('reconnect', function () {
    console.log(new Date().toLocaleTimeString(),'Reconnecting...')
  })

  client?.on('close', function () {
    console.log(new Date().toLocaleTimeString(),'Disconnected')
  })

  client?.on('disconnect', function (packet) {
    console.log(new Date().toLocaleTimeString(),'disconnect',packet)
  })

  client?.on('offline', function () {
    console.log(new Date().toLocaleTimeString(),'offline')
  })


  function on(type: string, callback: Function) {
    events[type] = callback;
  }

  function off(type: string) {
    Reflect.deleteProperty(events, type);
  }

  function emit(topic: string, message: Buffer) {
    for (const key in events) {
      events[key](topic, message);
    }
  }

  function publicTo(
    topic: string,
    message: string | Buffer,
    opts: mqtt.IClientPublishOptions,
    callback?: mqtt.PacketCallback | undefined
  ) {
    client?.publish(topic, message, opts, callback);
  }

  function reconnect(options?: mqtt.IClientOptions | undefined) {
    client?.reconnect(options);
  }

  function subscribe(
    topic: string | string[],
    opts: mqtt.IClientSubscribeOptions,
    callback?: mqtt.ClientSubscribeCallback | undefined
  ) {
    client?.subscribe(topic, opts, callback);
  }

  function unsubscribe(
    topic: string | string[],
    opts?: Object | undefined,
    callback?: mqtt.PacketCallback | undefined
  ) {
    client?.unsubscribe(topic, opts, callback);
  }

  function destroy() {
    if (client?.connected) {
      try {
        client.end();
        console.log('Successfully disconnected!');
      } catch (error) {
        console.log('Disconnect failed', error);
      }
    }
  }

  const mqttClient: MQTTClient = {
    publicTo,
    reconnect,
    on,
    off,
    subscribe,
    unsubscribe,
    destroy,
    install(app: App) {
      app.config.globalProperties.$mqttClient = mqttClient;

      app.provide(mqttKey, mqttClient);
    }
  };

  return mqttClient;
}
